在上篇我們提到希望最終的程式碼是呈現這樣
$crawler = new PttCrawler();
// 抓取所有看版及文章
$crawler->all();
// 抓取特定看版及看版文章
$crawler->get($boardName);
所以我們的第一步是可以把 PttCrawler 的所有程式移到到 Crawlers/Home.php 裡,在移動程式碼之前請先執行一次測試確保綠燈後再把程式碼調整為
<?php
// src/Crawlers/Home.php
namespace Recca0120\Ithome30\Crawlers;
use GuzzleHttp\Psr7\Request;
use Psr\Http\Client\ClientInterface;
class Home
{
public function __construct(private ClientInterface $httpClient)
{
}
public function all()
{
$request = new Request('GET', 'https://www.ptt.cc/bbs/hotboards.html');
$response = $this->httpClient->sendRequest($request);
$html = (string) $response->getBody();
return array_map(
fn (string $row) => $this->parseCols($row),
$this->parseRows($html)
);
}
private function parseCols($row)
{
preg_match('/href="(?<url>.+)"/', $row, $matched);
preg_match_all('/"board-(?<name>\w+)">(?<value>.+?)<\/div>/', $row, $matches);
$cols = ['url' => 'https://www.ptt.cc' . $matched['url']];
foreach (array_keys($matches[0]) as $index) {
$name = $matches['name'][$index];
$value = $matches['value'][$index];
$cols[$name] = str_replace('◎', '', strip_tags($value));
}
return $cols;
}
private function parseRows($html)
{
preg_match_all('/<a\sclass="board"[^>]*>.+?<\/a>/s', $html, $matches);
return $matches[0];
}
}
<?php
// src/PttCrawler.php
namespace Recca0120\Ithome30;
use Psr\Http\Client\ClientInterface;
use Recca0120\Ithome30\Crawlers\Home;
class PttCrawler
{
public function __construct(private ClientInterface $httpClient)
{
}
public function all()
{
$crawler = new Home($this->httpClient);
return $crawler->all();
}
}
調整完畢後再執行一次測試確保再次得到綠燈。
不進行重構,我們則會在 PttCrawler 這隻程式接著寫出文章列表的程式,如果今天的需求再增加了需要分析文章的回覆呢?是不是 PttCrawler 這隻程式就會越來越肥大了?而且職責就不單一了(負責分析看版、看版文章)!
這一步的重構是非常重要的,我們可以建立各個不同 class 來負責個各個不同的頁面,例如
這樣是不是明確多了?
寫測試最重要的是程式開發及重構,驗證只是程式開發及重構的一環,如果把驗證視為測試最重要的一件事,那對於開發人員來說,寫測試真的是浪費時間啊